<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2016/6/14
 * Time: 14:13
 */

namespace app\common\util\weixin;

use app\common\util\CUrl;

/**
 * Class OAuth
 * * 微信OAuth2.0获取认证
 * @package app\common\util\weixin
 */
class OAuth
{
    /**
     * Description: 获取CODE
     * @param $scope snsapi_base不弹出授权页面，只能获得OpenId;snsapi_userinfo弹出授权页面，可以获得所有信息
     * 将会跳转到redirect_uri/?code=CODE&state=STATE 通过GET方式获取code和state
     */
    public static function getCode($redirect_uri, $state = 1, $scope = 'snsapi_base')
    {
        //公众号的唯一标识
        $appid = AccessToken::getAppId();
        $redirect_uri = urlencode($redirect_uri);
        $response_type = 'code';
        //构造请求微信接口的URL
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $appid . '&redirect_uri=' . $redirect_uri . '&response_type=' . $response_type . '&scope=' . $scope . '&state=' . $state . '&connect_redirect=1#wechat_redirect';
        header('Location: ' . $url);
    }

    /**
     * Description: 通过code换取网页授权access_token
     * 首先请注意，这里通过code换取的网页授权access_token,与基础支持中的access_token不同。
     * 公众号可通过下述接口来获取网页授权access_token。
     * 如果网页授权的作用域为snsapi_base，则本步骤中获取到网页授权access_token的同时，也获取到了openid，snsapi_base式的网页授权流程即到此为止。
     * @param $code getCode()获取的code参数
     *
     * @return Array(access_token, expires_in, refresh_token, openid, scope)
     */
    public static function getAccessTokenAndOpenId($code)
    {
        //填写为authorization_code
        $grant_type = 'authorization_code';
        //构造请求微信接口的URL
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . AccessToken::getAppId() . '&secret=' . AccessToken::getSecretId() . '&code=' . $code . '&grant_type=' . $grant_type . '';
        //请求微信接口, Array(access_token, expires_in, refresh_token, openid, scope)
        return json_decode(CUrl::httpGet($url), true);
    }

    /**
     * 刷新access_token（如果需要）
     * 由于access_token拥有较短的有效期，当access_token超时后，可以使用refresh_token进行刷新，refresh_token拥有较长的有效期（7天、30天、60天、90天），当refresh_token失效的后，需要用户重新授权。
     * @param $refreshToken 通过本类的第二个方法getAccessTokenAndOpenId可以获得一个数组，数组中有一个字段是refresh_token，就是这里的参数
     *
     * @return array(
     * "access_token"=>"网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同",
     * "expires_in"=>access_token接口调用凭证超时时间，单位（秒）,
     * "refresh_token"=>"用户刷新access_token",
     * "openid"=>"用户唯一标识",
     * "scope"=>"用户授权的作用域，使用逗号（,）分隔")
     */
    public static function refreshToken($refreshToken)
    {
        $queryUrl = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=' . AccessToken::getAppId() . '&grant_type=refresh_token&refresh_token=' . $refreshToken;
        return json_decode(CUrl::httpGet($queryUrl), true);
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     * 如果网页授权作用域为snsapi_userinfo，则此时开发者可以通过access_token和openid拉取用户信息了。
     * @param $accessToken 网页授权接口调用凭证。通过本类的第二个方法getAccessTokenAndOpenId可以获得一个数组，数组中有一个字段是access_token，就是这里的参数。注意：此access_token与基础支持的access_token不同
     * @param $openId 用户的唯一标识
     * @param $lang 返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
     *
     * @return array("openid"=>"用户的唯一标识",
     * "nickname"=>'用户昵称',
     * "sex"=>"1是男，2是女，0是未知",
     * "province"=>"用户个人资料填写的省份"
     * "city"=>"普通用户个人资料填写的城市",
     * "country"=>"国家，如中国为CN",
     * //户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空
     * "headimgurl"=>"http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
     * //用户特权信息，json 数组，如微信沃卡用户为chinaunicom
     * "privilege"=>array("PRIVILEGE1", "PRIVILEGE2"),
     * );
     */
    public static function getUserInfo($accessToken = '', $openId = '', $lang = 'zh_CN')
    {
        if (empty($accessToken)) {
            $userinfo = OAuth::getSNAInfo(null, 'snsapi_userinfo');
            if (empty($userinfo['access_token'])) {
                die;
            }
            $accessToken = $userinfo['access_token'];
            $openId = $userinfo['openid'];
        }
        $queryUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $accessToken . '&openid=' . $openId . '&lang=' . $lang;
        $rt = json_decode(CUrl::httpGet($queryUrl), true);
        return $rt;
    }

    public static function getUserInfo2($accessToken = '', $openId = '', $lang = 'zh_CN')
    {
        if (empty($accessToken)) {
            $userinfo = OAuth::getSNAInfo(null, 'snsapi_userinfo,snsapi_health_realtime,snsapi_health_history','sportVersion3');
            if (empty($userinfo['access_token'])) {
                die;
            }
            $accessToken = $userinfo['access_token'];
            $openId = $userinfo['openid'];
        }
        $queryUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $accessToken . '&openid=' . $openId . '&lang=' . $lang;
        $rt = json_decode(CUrl::httpGet($queryUrl), true);
        return $rt;
    }

    /**
     * 检验授权凭证（access_token）是否有效
     * @param $accessToken 网页授权接口调用凭证。通过本类的第二个方法getAccessTokenAndOpenId可以获得一个数组，数组中有一个字段是access_token，就是这里的参数。注意：此access_token与基础支持的access_token不同
     * @param $openId
     * @return array("errcode"=>0,"errmsg"=>"ok")
     */
    public static function checkAccessToken($accessToken, $openId)
    {
        $queryUrl = 'https://api.weixin.qq.com/sns/auth?access_token=' . $accessToken . '&openid=' . $openId;
        return json_decode(CUrl::httpGet($queryUrl), true);
    }

    public static function getOpenid()
    {
        static $_openid;
        if (!empty($_openid)) {
            return $_openid;
        } else if (!empty(session('wxopenid'))) {
            return session('wxopenid');
        }
        $_openid = self::getSNAInfo('openid');
        session('wxopenid', $_openid);
        return $_openid;
    }

    public static function getSNAInfo($field = null, $scope = 'snsapi_base', $state = 1)
    {
        //通过code获得openid
        if (!isset($_GET['code'])) {
            //触发微信返回code码
            self::getCode(ccnn_request_url(), $state, $scope);
        } else {
            //获取code码，以获取openid
            $result = self::getAccessTokenAndOpenId($_GET['code']);
            unset($_GET['code']);
            if (!empty($result)) {
                if (isset($result['errcode']) && $result['errcode'] != 0) {
                    return '';
                }
                if (empty($field)) {
                    return $result;
                }
                return $result[$field];
            }
            return '';
        }
    }

}